#include "BakAndRecvBak.h"

//************************************
// Method:    	BakData_ANA				从站解析备份文件
// Programmer:  lww
// Time:		2019/2/16
// Returns:   	bool					true:接收字节数正确；false：错误
// Parameter: 	void * Data				数据区头指针
// Parameter: 	int len					数据包长度
// Parameter: 	short Head				报头
// Parameter: 	short Tail				报尾
//************************************
bool BakData_ANA(void* Data, int len, short Head, short Tail)
{
#define MEMREAD1(var)	MEMREAD(var, Data)
#define WRONG_DEAL	{\
	printf("Analyze bak data wrong!\r\n");\
	return false;\
}

	int i;
	int _iLen = 0;
	short Model_Num = 0;
	int Model_ID, Model_Type;
	short tmp_short;
	short ptr_off;

	//< duan1005
	/*printf("BakData_ANA-the current role is %d\r\n", SYS_Role);
	printf("BakData_ANA-ERROR-the current role is MASTER but in this SLAVE process\r\n");

	if (SYS_Role == Slave_Role)
		printf("BakData_ANA-Not care above ERROR--the current role is SLAVE\r\n");*/

	//< 校验报头
	MEMREAD1(tmp_short);
	if (tmp_short != Head)
		WRONG_DEAL;

	//< 读出当前指针到报尾的指针的距离，校验报尾
	MEMREAD1(ptr_off);
	memcpy(&tmp_short, (char*)(Data) + ptr_off, sizeof(tmp_short));
	if (tmp_short != Tail)
		WRONG_DEAL;

	//< 备份的模块数量
	MEMREAD1(Model_Num);

	//< 循环解析各个模块
	for (i = 0; i < Model_Num; i++)
	{
		MEMREAD1(Model_Type);
		MEMREAD1(Model_ID);
		_iLen += ANASAMA(&Model_List[Model_Type], Model_ID, &Data);
	}

	if (_iLen != (int)(len - sizeof(tmp_short)))
		WRONG_DEAL;

	return true;

#undef WRONG_DEAL
#undef MEMREAD1
}


//************************************
// Method:    	tRecvBak				从站接收备份线程
// Programmer:  lww
// Time:		2019/2/16
// Returns:   	void *
// Parameter: 	void * arg
//************************************
void *tRecvBak(void* arg)
{
#define PACK_MAXNUM	2048

	int sock;
	short Head = 2601;				//< 报头
	short Tail = 3420;				//< 报尾
	char Data2Recv[PACK_MAXNUM];	//< 存放数据包的数组
	short len;

	printf("the Kernel_%s is %d\r\n", "tRecvBak_ID", syscall(SYS_gettid));			//< duan20200610
	//< 初始化UDP设置
	if (false == UDP_Init(&sock, RECVBAKDATA_PORT, 0, 0, UDP_RECV_STATUS,nullptr)) { return 0; }

	while (1)
	{
		//< printf("the current role is %d\r\n", SYS_Role);
		if (SYS_Role == Slave_Role)
		{
			/*printf("tRecvBak-the current role is %d\r\n", SYS_Role);
			printf("tRecvBak-ERROR-the current role is MASTER but in this SLAVE process\r\n");

			if (SYS_Role == Slave_Role)
				printf("tRecvBak-Not care above ERROR--the current role is SLAVE\r\n");*/

			//< 接收数据
			memset(Data2Recv, 0, sizeof(Data2Recv));									
			len = (short)UDP_Recv_Any_Bytes(&sock, Data2Recv, PACK_MAXNUM);
			if (len == -1)
				continue;
			//< 解析报文
			if (Slave_Role == SYS_Role)																							//< duan1005
				BakData_ANA(Data2Recv, len, Head, Tail);
		}
		else
			ExactDelay(2000);

	}
	close(sock);//< 断开连接

#undef PACK_MAXNUM
}


//************************************
// Method:    	BakData_PACK_Make			备份文件打包程序
// Programmer:  lww
// Time:		2019/2/16
// Returns:   	int							打包长度
// Parameter: 	void * Data					数据包头指针
// Parameter: 	short Head					报头
// Parameter: 	short Tail					报尾
// Parameter: 	int Limit_Len				单次数据包长度限制
// Parameter: 	short * SaveModel_Num		存储的模块的数量
//************************************
int BakData_PACK_Make(void* Data, short Head, short Tail, int Limit_Len, short* SaveModel_Num, int* Model_Total_Count)
{
#define MEMWRITE1(name)	MEMWRITE(name, Data);
	int _iLen = 0;
	short tmp_short = 0;
	/*static int i = 0;*/					//< duan20200503注释
	void* Data1 = NULL;
	int Model_ID, Model_Type;

	//< 报头
	MEMWRITE1(Head);

	//< 数据区长度，此处先保留该存储位置，稍后再对其进行存储
	Data1 = Data;
	MEMWRITE1(tmp_short);
	_iLen = (int)(_iLen - sizeof(tmp_short));

	//< 第三个数据存储本次要备份的模块数量，这个数据等打包完成后最后写入，此处先保留该存储位置，稍后再对其进行存储
	MEMWRITE1(SaveModel_Num[0]);
	_iLen = (int)(_iLen - sizeof(SaveModel_Num[0]));

	for ( ; Model_Total_Count[0] < Model_TotalNum; )
	{
		Model_ID = Model_Calcu_ID[Model_Total_Count[0]];
		Model_Type = Model_Calcu_Type[Model_Total_Count[0]];
		_iLen += BAKSAMA(&Model_List[Model_Type], Model_ID, &Data, SaveModel_Num);
		
		Model_Total_Count[0]++;
		if (_iLen >= Limit_Len)
			break;
	}
	//if (i >= Model_TotalNum)											//< duan20200503注释
	//	i = 0;

	//< 写第二个数据
	tmp_short = (short)(_iLen - sizeof(Head) + sizeof(SaveModel_Num[0]));//< 等于目前已经计数的长度减去报头，加上要广播模块数量数据的长度
	MEMWRITE(tmp_short, Data1);

	//< 写第三个数据
	MEMWRITE(SaveModel_Num[0], Data1);
	
	//< 报尾
	MEMWRITE1(Tail);
	return _iLen;
#undef MEMWRITE1
}


//************************************
// Method:    	tBakAndRecvBak				主从备份线程
// Programmer:  lww
// Time:		2019/2/16
// Returns:   	void *
// Parameter: 	void * arg
//************************************
void *tBakAndRecvBak(void* arg)
{
#define PACK_MAXNUM	2048
#define LIMIT_LEN	512
#define EACH_UDP_PACK_SEND_DELAY_TIME 1	//< Shike20210516 长兴现场发现UDP广播包与包之间没有延时，发送太快，导致从站长时间因丢包无法更新自己的硬点当前值，这样主从切换就很明显会跳变
	int sock;
	static int Model_Total_Count = 0;
	struct sockaddr_in NetC;
	timer_t BakData_Timer;
	struct timespec time;
	short Head = 2601;				//< 报头
	short Tail = 3420;				//< 报尾
	char Data2Send[PACK_MAXNUM];	//< 存放数据包的数组
	int _iLen = 0;
	short SaveModel_Num = 0;		//< 当前数据包广播的模块数量
	pthread_t tRecvBak_ID = 0;

	printf("the Kernel_%s is %d\r\n", "tBakAndRecvBak_ID", syscall(SYS_gettid));			//< duan20200610
	//< 初始化UDP设置
	if (false == UDP_Init(&sock, BAKDATA_PORT, 0, 0, UDP_SEND_STATUS, nullptr)) { return 0; }

	//< 开启接收备份数据的线程
	THREAD_CREATE_FAILED(Thread_Create("tRecvBak_ID", &tRecvBak_ID, NULL, SCHED_POLICY, 89, true, tRecvBak, CONTROL_CORE, NULL));

	//< 设置发送到的IP地址及端口
	Addr_Set(&NetC, BAKDATA_PORT, inet_addr(NETC_IP_BC));

	//< 设置广播周期
	MS2TimeSpec(&time, BAKDATA_PERIOD);

	//< 开启定时中断
	Timer_Create(&BakData_Timer, BakDataSIG, &time);
	while (1)
	{
		if (SYS_Role == Master_Twins_Role)
		{
			//< 等待信号量释放进行广播操作
			/*MUTEX_LOCK(BakData_Mutex, "BakData_Mutex lock failed");*/
			SEM_WAIT(BakDataSemId, "BakDataSemId wait failed");

			while (Model_Total_Count < Model_TotalNum)
			{
				SaveModel_Num = 0;
				//< 数据打包
				_iLen = BakData_PACK_Make(Data2Send, Head, Tail, LIMIT_LEN, &SaveModel_Num, &Model_Total_Count);

				if (SaveModel_Num > 0)
				{
					ExactDelay(EACH_UDP_PACK_SEND_DELAY_TIME);		//< Shike20210516 UDP包之间加一个小延时
					//< 发送数据
					if (-1 == UDP_Send(&sock, &NetC, (char*)Data2Send, _iLen))
						break;
				}
			}
			if (Model_Total_Count >= Model_TotalNum)				//< duan20200503添加
				Model_Total_Count = 0;
		}
		else
			RoughDelay_S(2);
	}
	close(sock);//< 断开连接
#undef LIMIT_LEN
#undef PACK_MAXNUM
#undef EACH_UDP_PACK_SEND_DELAY_TIME
}
